global popart_asm

section .data

section .text
;void tiles_asm(unsigned char *src,
;              unsigned char *dst,
;              int filas,
;              int cols,
;              int src_row_size,
;              int dst_row_size );

global popart_asm

%define i r10
%define j r11
%define filas rcx
%define cols rdx

;b g r 
section .data
borrarfruta: db 255,255,255,255,0,0,0,0,0,0,0,0,0,0,0,0
mask: db 0x00, 0x01, 0x02, 0xFF, 0x03, 0x04, 0x05, 0xFF, 0x06,0x07,0x08,0xFF, 0x09,0x0A,0x0B,0xFF
a43bytes: db 0x00, 0x01, 0x02, 0x04, 0x05, 0x06, 0x08, 0x09,0x0a,0x0c,0x0d,0x0e, 0xFF,0xFF,0xFF,0xFF
colores0: db 255,0,0,0, 255,0,0,0, 255,0,0,0, 255,0,0,0
colores1: db 127,0,127,0, 127,0,127,0 ,127,0,127,0 ,127,0,127,0
colores2: db 255,0,255,0 ,255,0,255,0, 255,0,255,0, 255,0,255,0
colores3: db 0,0,255,0, 0,0,255,0, 0,0,255,0, 0,0,255,0
colores4: db 0,255,255,0, 0,255,255,0 ,0,255,255,0 ,0,255,255,0 
mask153: dd 153,153,153,153
mask306: dd 306,306,306,306
mask459: dd 459, 459, 459, 459
mask612: dd 612, 612, 612, 612

section .text


;void popart_asm(unsigned char *src,
;          	unsigned char *dst,
;          	int filas,
;          	int cols,
;          	int src_row_size,
;          	int dst_row_size );

popart_asm:

	
push rbp
mov rbp, rsp
push r12
push r13
push r14
push r15

;rdi = unsigned char *src,
;rsi = unsigned char *dst,
;rdx = int filas,
;rcx = int cols,
;r8 = int src_row_size
;r9 = int dst_row_size

xor j, j
xor i, i
xor r14, r14
xor r15, r15


pxor xmm3, xmm3
pxor xmm2, xmm2

xor rax, rax
mov r8d, r8d
mov r9d, r9d
mov edx, edx
mov ecx, ecx

lea cols, [2*cols + cols]

.fil:

	cmp i, filas
        je  .fin

	xor j,j
	mov r14, rsi
	mov r15, rdi

.col:

	cmp j, cols
        je .listo
	
	movdqu xmm0,  [rdi]

.procesar:
;no se usan xmm1, xmm8
;levantar datos en 2 xmm, procesar uno y rotarlos.

	pshufb xmm0 , [mask]

	movdqu xmm2, xmm0
	movdqu xmm3, xmm0
	pxor xmm0, xmm0
 
	punpcklbw xmm3, xmm0    	;|00|0r|0g|0b|00|0r|0g|0b|
	punpckhbw xmm2, xmm0  		;|00|0r|0g|0b|00|0r|0g|0b|

	phaddw xmm3, xmm3   		;| * | * | * | * |r+0|g+b|r+0|g+b|
	phaddw xmm3, xmm3   		;| * | * | * | * | * | * |r+g+b|r+g+b|	 
	phaddw xmm2, xmm2 
	phaddw xmm2, xmm2   		;| * | * | * | * | * | * |r+g+b|r +g+b|
	
	pand xmm3, [borrarfruta]
	pand xmm2, [borrarfruta]

	pslldq xmm2, 4
	paddw xmm2, xmm3		;xmm2 = | 0 | 0 | 0 | 0 |r+g+b|r+g+b|r+g+b|r+g+b|
	pxor xmm7,xmm7
	punpcklwd xmm2, xmm7		;xmm2 = |0 0 r+g+b|0 0r+g+b|0 0 r+g+b| 0 0 r+g+b| doubles word
	movdqu xmm10, [mask153]
	pcmpgtd xmm10, xmm2    		; 153 > xmm2, resultados en xmm10

	movdqu xmm11, [mask153]
	movdqu xmm13, xmm2
	movdqu xmm14, xmm2
	movdqu xmm15, xmm2
	pcmpeqd xmm15, xmm11		; xmm2 = 153
	pcmpgtd xmm14, xmm11     	; xmm2 > 153
	por xmm14, xmm15		; xmm15 libre, xmm14 máscara para >= 153
	movdqu xmm11, [mask306]
	pcmpgtd xmm11, xmm13   		; máscara para < 306,
	pand xmm14 , xmm11		; máscara  153 <= xmm2 <306, resultado en xmm14

	movdqu xmm11, [mask306]
	movdqu xmm13, xmm2
	movdqu xmm12, xmm2
	movdqu xmm15, xmm2
	pcmpeqd xmm15, xmm11		; xmm2 = 306
	pcmpgtd xmm12, xmm11    	; xmm2 > 306
	por xmm12, xmm15		; xmm15 libre, máscara para >= 306, resultado en xmm12
	movdqu xmm11, [mask459]
	pcmpgtd xmm11, xmm13   		; máscara para < 459,
	pand xmm12, xmm11		; máscara  306 <= pixeles <459, resultado en xmm12
	
	movdqu xmm11, [mask459]
	movdqu xmm13, xmm2
	movdqu xmm9, xmm2
	movdqu xmm15, xmm2
	pcmpeqd xmm15, xmm11		; xmm2 = 459
	pcmpgtd xmm9, xmm11     	; xmm2 > 459
	por xmm9, xmm15			; xmm15 libre, máscara para >= 459
	movdqu xmm11, [mask612]
	pcmpgtd xmm11, xmm13   		; máscara para < 612,
	pand xmm9, xmm11		; máscara  459 <= xmm2 <612, resultado xmm9

	pxor xmm6, xmm6			; pongo los resultados de las mascaras en xmm6

	por xmm6, xmm9			
	por xmm6, xmm12			
	por xmm6, xmm14
	por xmm6, xmm10 		; si niego xmm6 obtengo el resultado de la ultima guarda

	pcmpeqd xmm5, xmm5		; pongo xmm5 = 1
	pxor xmm6, xmm5			; en xmm6 tengo el resultado de la ultma guarda
	
	pand xmm10, [colores0];		
	pand xmm14, [colores1];
	pand xmm12, [colores2];
	pand xmm9,  [colores3];
	pand xmm6,  [colores4];

	pxor xmm2, xmm2

	paddd xmm2, xmm9
	paddd xmm2, xmm12
	paddd xmm2, xmm14
	paddd xmm2, xmm10
	paddd xmm2, xmm6
	
	pshufb xmm2, [a43bytes]

	cmp rax, 1
	je .procesaMitad
	cmp rax, 2
	je .listo
	
	movdqu [rsi], xmm2
	
	add j, 12
	add rsi, 12
        add rdi, 12

	add j, 16
	cmp j, cols
        jg .CheckPadding
	sub j, 16

	jmp .col

.CheckPadding:

	xor r12, r12
	xor r13, r13
	xor rax, rax

	sub j, 16
	mov r12, cols
	sub r12, 16     			; r12 distancia al padding  
	mov r13, j
	sub r13, r12
	
	sub rsi, r13				; 16 bytes por procesar 
	sub rdi, r13
	
	pxor xmm4, xmm4
	
	movdqu xmm0, [rdi]
	psrldq xmm0, 1 
	mov rax, 1 		
	jmp .procesar

.procesaMitad:

	pslldq xmm2, 7    		        ; pongo en 0 en la parte mas significativa del registro
	psrldq xmm2, 6
	

	pxor xmm4, xmm4
	movdqu xmm4, xmm2
	
	movdqu xmm0, [rdi]
	psrldq xmm0, 10				; proceso los 2 bytes que me quedan
	mov rax, 2
	jmp .procesar

.listo:

	pslldq xmm2, 10
	
	por xmm2, xmm4
	movdqu xmm4, [rsi]
	pslldq xmm4, 15
	psrldq xmm4, 15
	por xmm2, xmm4
	movdqu [rsi], xmm2

	mov rsi, r14
	add rsi, r9 

	mov rdi, r15
	add rdi, r8

	xor rax, rax
	
	add i, 1
	jmp .fil

.fin:

	pop r15
	pop r14
	pop r13
	pop r12
	pop rbp
	ret
